package rlpw.swing;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import rlpw.util.UniqueList;

public class DefaultModel<T> extends UniqueList<T> implements Model<T> {

    private List<View<T>> viewlist = new ArrayList<View<T>>();
    private EventListenerList listeners = new EventListenerList();

    public DefaultModel() {
    }

    public DefaultModel(Collection<T> c) {
        addAll(c);
    }

    public void updateViews() {
        for (View<T> v : viewlist) {
            v.updateView();
        }
    }

    public void addView(View<T> view) {
        if (view == null) {
            return;
        }
        view.setDataModel(this);
        viewlist.add(view);
    }

    public void removeView(View<T> view) {
        if (view == null) {
            return;
        }
        view.setDataModel(null);
        viewlist.remove(view);
    }

    @Override
    public boolean add(T e) {
        int index = size();
        if (super.add(e)) {
            fireIntervalAdded(this, index, index);
            return true;
        }
        return false;

    }

    @Override
    public void add(int index, T element) {
        super.add(index, element);
        fireIntervalAdded(this, index, index);
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> c) {
        if (super.addAll(index, c)) {
            if (!c.isEmpty()) {
                fireIntervalAdded(this, index, index + c.size() - 1);
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        return addAll(size(), c);
    }

    @Override
    public void clear() {
        int index = size() - 1;
        super.clear();
        if (index >= 0) {
            fireIntervalRemoved(this, 0, index);
        }
    }

    @Override
    public T remove(int index) {
        fireIntervalRemoved(this, index, index);
        return super.remove(index);
    }

    @Override
    public boolean remove(Object o) {
        int index = indexOf(o);
        if (super.remove(o)) {
            fireIntervalRemoved(this, index, index);
            return true;
        }
        return false;
    }

    @Override
    protected void removeRange(int fromIndex, int toIndex) {
        super.removeRange(fromIndex, toIndex);
        fireIntervalRemoved(this, fromIndex, toIndex);
    }

    @Override
    public T set(int index, T element) {
        fireContentsChanged(this, index, index);
        return super.set(index, element);
    }

    public void addListDataListener(ListDataListener l) {
        listeners.add(ListDataListener.class, l);
    }

    public void removeListDataListener(ListDataListener l) {
        listeners.remove(ListDataListener.class, l);
    }

    protected synchronized void fireContentsChanged(Object source, int index0, int index1) {
        updateViews();
        ListDataEvent event = new ListDataEvent(source, ListDataEvent.CONTENTS_CHANGED, index0, index1);
        for (ListDataListener l : listeners.getListeners(ListDataListener.class)) {
            l.contentsChanged(event);
        }
    }

    protected synchronized void fireIntervalAdded(Object source, int index0, int index1) {
        updateViews();
        ListDataEvent event = new ListDataEvent(source, ListDataEvent.INTERVAL_ADDED, index0, index1);
        for (ListDataListener l : listeners.getListeners(ListDataListener.class)) {
            l.intervalAdded(event);
        }
    }

    protected synchronized void fireIntervalRemoved(Object source, int index0, int index1) {
        updateViews();
        ListDataEvent event = new ListDataEvent(source, ListDataEvent.INTERVAL_REMOVED, index0, index1);
        for (ListDataListener l : listeners.getListeners(ListDataListener.class)) {
            l.intervalRemoved(event);
        }


    }
}
